home *** CD-ROM | disk | FTP | other *** search
/ CD Exchange / CD Exchange - Volume 1.iso / d.t.p / utils / others / pcal / pcalutil.c < prev    next >
C/C++ Source or Header  |  1992-02-21  |  21KB  |  981 lines

  1. /*
  2.  * pcalutil.c - utility routines for Pcal
  3.  *
  4.  * Contents:
  5.  *
  6.  *        alloc
  7.  *        calc_day
  8.  *        calc_weekday
  9.  *        calc_year_day
  10.  *        ci_strcmp
  11.  *        ci_strncmp
  12.  *        copy_text
  13.  *        cvt_escape
  14.  *        find_executable
  15.  *        getline
  16.  *        is_valid
  17.  *        loadwords
  18.  *        mk_filespec
  19.  *        mk_path
  20.  *        normalize
  21.  *        note_box
  22.  *        note_day
  23.  *        split_date
  24.  *        trnlog
  25.  *
  26.  * Revision history:
  27.  *
  28.  *    4.3    AWR    11/22/91    added special case to loadwords():
  29.  *                    split -<flag>"<text>" into two words
  30.  *
  31.  *                    removed octal/hex escape functionality
  32.  *                    from getline() to new routine
  33.  *                    cvt_escape() (for use elsewhere)
  34.  *
  35.  *            10/25/91    added parameters to loadwords() and
  36.  *                    getline() to avoid always using same
  37.  *                    global data
  38.  *
  39.  *            10/15/91    revised UN*X mk_filespec() to translate
  40.  *                    "~/" in path name as well as file name
  41.  *
  42.  *    4.2    AWR    10/08/91    support -[kK] flags (cf. note_box())
  43.  *
  44.  *            10/03/91    added note_box(), note_day()
  45.  *
  46.  *    4.11    AWR    08/20/91    documented find_executable()
  47.  *
  48.  *    4.02    AWR    06/07/91    added find_executable()
  49.  *
  50.  *    4.0    AWR    02/24/91    Revised getline() and copy_text() to
  51.  *                    handle C-style escapes of characters
  52.  *                    and octal/hex numbers
  53.  *
  54.  *        AWR    02/19/91    Added support for negative ordinals
  55.  *                    in calc_day(), calc_year_day()
  56.  *
  57.  *        AWR    02/04/91    Added calc_year_day()
  58.  *
  59.  *        AWR    01/15/91    Extracted from pcal.c
  60.  *
  61.  */
  62.  
  63.  
  64. /*
  65.  * Standard headers:
  66.  */
  67.  
  68. #include <stdio.h>
  69. #include <ctype.h>
  70. #include <string.h>
  71.  
  72. /*
  73.  * Pcal-specific definitions:
  74.  */
  75.  
  76. #include "pcaldefs.h"
  77. #include "pcalglob.h"
  78. #include "pcallang.h"
  79.  
  80. /*
  81.  * Macros:
  82.  */
  83.  
  84. /* skip over numeric field and subsequent non-numeric characters */
  85. #define SKIP_FIELD(p) \
  86.     do { while (*p && isdigit(*p)) p++; \
  87.          while (*p && !isdigit(*p)) p++; } while (0)
  88.  
  89. /* guarantee that a path is terminated by the END_PATH character */
  90. #define TERM_PATH(path) \
  91.     do { char *p;    \
  92.         if ((p = P_LASTCHAR(path)) && *p != END_PATH) \
  93.             *++p = END_PATH, *++p = '\0'; } while (0)
  94.  
  95.  
  96. /*
  97.  * General-purpose utility routines
  98.  */
  99.  
  100.  
  101. /*
  102.  * alloc - interface to calloc(); terminates if unsuccessful
  103.  */
  104. #ifdef PROTOS
  105. char *alloc(int size)
  106. #else
  107. char *alloc(size)
  108.     int size;
  109. #endif
  110. {
  111.     char *p;
  112.  
  113.     if (size == 0)        /* not all calloc()s like null requests */
  114.         size = 1;
  115.  
  116.     if ((p = calloc(1, size)) == NULL) {
  117.         FPR(stderr, E_ALLOC_ERR, progname);
  118.         exit(EXIT_FAILURE);
  119.     }
  120.  
  121.     return p;
  122. }
  123.  
  124.  
  125. /*
  126.  * ci_str{n}cmp - case-insensitive flavors of strcmp(), strncmp()
  127.  */
  128. #ifdef PROTOS
  129. int ci_strcmp(register char *s1,
  130.           register char *s2)
  131. #else
  132. int ci_strcmp(s1, s2)
  133.     register char *s1, *s2;
  134. #endif
  135. {
  136.     register char c1, c2;
  137.  
  138.     for ( ; (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
  139.         if (c1 == '\0')
  140.             return 0;
  141.  
  142.     return c1 - c2;
  143. }
  144.  
  145.  
  146. #ifdef PROTOS
  147. int ci_strncmp(register char *s1,
  148.            register char *s2,
  149.            int n)
  150. #else
  151. int ci_strncmp(s1, s2, n)
  152.     register char *s1, *s2;
  153.     int n;
  154. #endif
  155. {
  156.     register char c1, c2;
  157.  
  158.     for ( ; --n >= 0 && (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
  159.         if (c1 == '\0')
  160.             return 0;
  161.  
  162.     return n < 0 ? 0 : c1 - c2;
  163. }
  164.  
  165.  
  166. /*
  167.  * Date calculation routines (see also macros in pcaldefs.h)
  168.  */
  169.  
  170.  
  171. /*
  172.  * normalize - adjust day in case it has crossed month (or year) bounds 
  173.  */
  174. #ifdef PROTOS
  175. void normalize(DATE *pd)
  176. #else
  177. void normalize(pd)
  178.     DATE *pd;        /* pointer to date */
  179. #endif
  180. {
  181.     int len;
  182.  
  183.     /* adjust if day is in previous or following month */
  184.  
  185.     while (pd->dd < 1) {
  186.         pd->yy = PREV_YEAR(pd->mm, pd->yy);
  187.         pd->mm = PREV_MONTH(pd->mm, pd->yy);
  188.         pd->dd += LENGTH_OF(pd->mm, pd->yy);
  189.     }
  190.  
  191.     while (pd->dd > (len = LENGTH_OF(pd->mm, pd->yy))) {
  192.         pd->dd -= len;
  193.         pd->yy = NEXT_YEAR(pd->mm, pd->yy);
  194.         pd->mm = NEXT_MONTH(pd->mm, pd->yy);
  195.     }
  196. }
  197.  
  198.  
  199. /*
  200.  * calc_day - calculate calendar date from ordinal date (e.g., "first Friday
  201.  * in November", "last day in October"); return calendar date if it exists, 
  202.  * 0 if it does not
  203.  */
  204. #ifdef PROTOS
  205. int calc_day(int ord,
  206.          int wkd,
  207.          int mm)
  208. #else
  209. int calc_day(ord, wkd, mm)
  210.     int ord;
  211.     int wkd;
  212.     int mm;
  213. #endif
  214. {
  215. #ifdef PROTOS
  216.     int first, last, day, (*pfcn)(int, int, int);
  217. #else
  218.     int first, last, day, (*pfcn)();
  219. #endif
  220.  
  221.     if (IS_WILD(wkd)) {    /* "day", "weekday", "workday", or "holiday" */
  222.         pfcn = pdatefcn[wkd - WILD_FIRST];
  223.         last = LENGTH_OF(mm, curr_year);
  224.  
  225.         if (ord < 0) {            /* search backwards */
  226.             for (day = last; 
  227.                  day >= 1 &&
  228.                 !((*pfcn)(mm, day, curr_year) && ++ord == 0);
  229.                  day--)
  230.                 ;
  231.         } else {            /* search forwards */
  232.             for (day = 1; 
  233.                  day <= last && 
  234.                 !((*pfcn)(mm, day, curr_year) && --ord == 0);
  235.                  day++)    
  236.                 ;
  237.         }
  238.         return is_valid(mm, day, curr_year) ? day : 0; 
  239.  
  240.     } else {        /* fixed weekday - calculate it */
  241.         first = (wkd - FIRST_OF(mm, curr_year) + 7) % 7 + 1;
  242.         if (ord < 0) {        /* get last (try 5th, then 4th) */
  243.             if (!is_valid(mm, last = first + 28, curr_year))
  244.                 last -= 7;
  245.             if (!is_valid(mm, day = last + 7 * (ord + 1),
  246.                 curr_year))
  247.                 day = 0;    
  248.         }
  249.         else 
  250.             if (!is_valid(mm, day = first + 7 * (ord - 1),
  251.                 curr_year))
  252.                 day = 0;
  253.  
  254.         return day;
  255.     }
  256.  
  257. }
  258.  
  259.  
  260. /*
  261.  * calc_year_day - calculate calendar date from ordinal date within year
  262.  * (e.g., "last Friday in year", "10th holiday in year"); if date exists,
  263.  * fill in pdate and return TRUE; else return FALSE
  264.  */
  265. #ifdef PROTOS
  266. int calc_year_day(int ord,
  267.           int wkd,
  268.           DATE *pdate)
  269. #else
  270. int calc_year_day(ord, wkd, pdate)
  271.     int ord;
  272.     int wkd;
  273.     DATE *pdate;
  274. #endif
  275. {
  276. #ifdef PROTOS
  277.     int incr, (*pfcn)(int, int, int);
  278. #else
  279.     int incr, (*pfcn)();
  280. #endif
  281.     DATE date;
  282.  
  283.     if (IS_WILD(wkd)) {    /* "day", "weekday", "workday", or "holiday" */
  284.         pfcn = pdatefcn[wkd - WILD_FIRST];
  285.  
  286.         if (ord < 0) {            /* nth occurrence backwards */
  287.             MAKE_DATE(date, DEC, 31, curr_year);
  288.             ord = -ord;
  289.             incr = -1;
  290.         } else {            /* nth occurrence forwards */
  291.             MAKE_DATE(date, JAN, 1, curr_year);
  292.             incr = 1;
  293.         }
  294.  
  295.         /* search for selected occurrence of specified wildcard */
  296.  
  297.         while (date.yy == curr_year &&
  298.                !((*pfcn)(date.mm, date.dd, date.yy) && --ord == 0)) {
  299.             date.dd += incr;
  300.             normalize(&date);
  301.         }
  302.  
  303.     } else {        /* fixed weekday - calculate it */
  304.         if (ord < 0)
  305.             MAKE_DATE(date, DEC,
  306.                   calc_day(-1, wkd, DEC) + 7 * (ord + 1),
  307.                   curr_year);
  308.         else
  309.             MAKE_DATE(date, JAN,
  310.                   calc_day(1, wkd, JAN) + 7 * (ord - 1),
  311.                   curr_year);
  312.         normalize(&date);
  313.     }
  314.  
  315.     return date.yy == curr_year ? (*pdate = date, TRUE) : FALSE;
  316. }
  317.  
  318.  
  319. /*
  320.  * calc_weekday - return the weekday (0-6) of mm/dd/yy (mm: 1-12)
  321.  */
  322. #ifdef PROTOS
  323. int calc_weekday(int mm,
  324.          int dd,
  325.          int yy)
  326. #else
  327. int calc_weekday(mm, dd, yy)
  328.     int mm;
  329.     int dd;
  330.     int yy;
  331. #endif
  332. {
  333.     return (yy + (yy-1)/4 - (yy-1)/100 + (yy-1)/400 + OFFSET_OF(mm, yy) +
  334.         (dd-1)) % 7;
  335. }
  336.  
  337.  
  338. /*
  339.  * note_day - translate n (from "note/<n>" spec) to appropriate note text
  340.  * day for mm/yy; return note text day if in range, 0 if not
  341.  */
  342. #ifdef PROTOS
  343. int note_day(int mm,
  344.          int n,
  345.          int yy)
  346. #else
  347. int note_day(mm, n, yy)
  348.     int mm;
  349.     int n;
  350.     int yy;
  351. #endif
  352. {
  353.     int day, lastday;
  354.  
  355.     if (n == 0)            /* convert 0 to appropriate default */
  356.         n = NOTE_DEFAULT;
  357.  
  358.     /* lastday depends on month length and presence (but not position) of
  359.      * small calendars
  360.      */
  361.     lastday = LAST_NOTE_DAY - (LENGTH_OF(mm, yy) - 28) -
  362.             (small_cal_pos == SC_NONE ? 0 : 2);
  363.  
  364.     /* count forward if n is positive, backward if negative */
  365.     day = (n > 0) ? FIRST_NOTE_DAY + n - 1 : lastday + n + 1;
  366.  
  367.     /* make sure result is valid for this month/year */
  368.     return (day >= FIRST_NOTE_DAY && day <= lastday) ? day : 0;
  369. }
  370.  
  371.  
  372. /*
  373.  * note_box - translate dd from note text day to box number for mm/yy,
  374.  * adjusting for presence and position of small calendars
  375.  */
  376. #ifdef PROTOS
  377. int note_box(int mm,
  378.          int dd,
  379.          int yy)
  380. #else
  381. int note_box(mm, dd, yy)
  382.     int mm;
  383.     int dd;
  384.     int yy;
  385. #endif
  386. {
  387.     int startbox = START_BOX(mm, yy), pc, nc;
  388.  
  389.     /* move starting box to second row if conflict with small calendars */
  390.     if ((pc = prev_cal_box[small_cal_pos]) == startbox ||
  391.         (nc = next_cal_box[small_cal_pos]) == startbox)
  392.         startbox += 7;
  393.  
  394.     dd -= FIRST_NOTE_DAY;        /* convert to note box number 0..13 */
  395.     dd += (pc == 0) + (nc == 1);    /* adjust for small calendars in 0, 1 */
  396.  
  397.     /* position box after calendar body if no room before */
  398.     return dd < startbox ? dd : dd + LENGTH_OF(mm, yy);
  399. }
  400.  
  401.  
  402. /*
  403.  * is_valid - return TRUE if m/d/y is a valid